#pragma once

#include <OmenConfig.h>

#include <string>
#include <vector>

namespace Omen 
{
    #pragma warning(disable:4251) // Disable warning about private member variable needs to have dll-interface to be used by clients of class 'this'

    class XmlDocument;
    class XmlNode;
    class XmlNodeAttribute;
    
    /// <summary>XmlDocument class represents a DOM (Document Object Model) created from an Omen XML-file</summary>
    class OMEN_API XmlDocument
    {
    public:
        XmlDocument();
        XmlDocument( const XmlDocument& other );
        virtual ~XmlDocument();

        void clear();                           /// <summary>This will erase the whole DOM</summary>
        void addRootNode( XmlNode& node );        /// <summary>Adds the given node as a rootnode
        std::vector<XmlNode>::iterator begin();    /// <summary>Returns the first root node in the document</summary>
        std::vector<XmlNode>::iterator end();    /// <summary>Returns the las node in the document</summary>
    
    protected:
    private:
        std::vector<XmlNode>    m_rootNodes;
    };

    class OMEN_API XmlReader 
    {
    public:
        XmlReader( const std::wstring& filename );
        virtual ~XmlReader();

        bool parseHeader(); /// <summary>This function will only parse the first root-node in the document</summary>
        bool parseDocument( bool bReadOnlyHeader = false ); /// <summary>Parses the DOM out of current file. Optionally only the header</summary>
        bool getDocument( XmlDocument& document );    /// <summary>Returns true if the document was returned in the document parameter, false otherwise</summary>

    protected:
        void parseAttributes( XmlNode& node, const std::wstring& strnode );
        bool parseNode( XmlNode& node, std::vector<std::wstring>::iterator& bufferIteratr, std::wstring& data_str = std::wstring() );
        
    protected:
    private:
        std::vector<std::wstring>    m_buffer;
        XmlDocument                    m_document;
    };

    

    class OMEN_API XmlNode
    {
    public:
        XmlNode( const std::wstring& name, XmlDocument& document );        /// <summary>Create a new root node</summary>
        XmlNode( const std::wstring& name, XmlNode& parent );                /// <summary>Create a new child node</summary>
        XmlNode( const XmlNode& other );        /// <suummary>copy ctor</summary>
        
        virtual ~XmlNode();
    
        XmlNode*                  parent();
        std::vector<XmlNode>&     children();
        std::vector<XmlNodeAttribute>& attributes();
        XmlDocument&              document();

        std::wstring&             name();
        void                      setName( const std::wstring& name );
        std::wstring&              data();
        void                       setData( const std::wstring& data );

        void addAttribute( XmlNodeAttribute& attribute );
        bool getAttribute( const std::wstring& attributeName, XmlNodeAttribute& attribute );
        void addChild( XmlNode node );

        XmlNode& operator=( const XmlNode& other );

    protected:

    private:
        XmlDocument&                    m_document;
        XmlNode*                        m_pParent;
        
        std::wstring                    m_nodeName;
        std::vector<XmlNode>            m_listChildren;
        std::vector<XmlNodeAttribute>    m_attributes;    /// <summary>Nodes can have a attributes. e.g. <mynode my_attrib="my_value"/> </summary>
        
        std::wstring                    m_comment;         /// <summary>Nodes can have a comment </summary>
        std::wstring                    m_data;             /// <summary>Node data</summary>
    };

    class OMEN_API XmlNodeAttribute
    {
    public:
        XmlNodeAttribute();
        XmlNodeAttribute( const std::wstring& attributeName, const std::wstring& attributeValue );

        std::wstring& name();
        std::wstring& value();

        bool operator==( const XmlNodeAttribute& other );
        bool operator==( const std::wstring& name );
        bool operator<( const XmlNodeAttribute& other );
    protected:
    private:
        std::wstring    m_name, m_value;
    };
    
#pragma warning(default:4251) // Set the default state of the warning
}